#pragma once
#include <dbformat.h>
#include <sstream>

namespace minidb
{

static uint64_t PackSequenceAndType(uint64_t seq, ValueType t)
{
    assert(seq <= kMaxSequenceNumber);
    assert(t <= kValueTypeForSeek);
    return (seq << 8) | t;
}

void AppendInternalKey(std::string *result, const ParsedInternalKey &key)
{
    result->append(key.user_key.data(), key.user_key.size());
    PutFixed64(result, PackSequenceAndType(key.sequence, key.type));
}

const char *InternalKeyComparator::Name() const
{
    return "leveldb.InternalKeyComparator";
}

int InternalKeyComparator::Compare(const Slice &akey, const Slice &bkey) const
{
    int r = user_comparator_->Compare(ExtractUserKey(akey), ExtractUserKey(bkey));
    if (r == 0)
    {
        const uint64_t anum = DecodeFixed64(akey.data() + akey.size() - 8);
        const uint64_t bnum = DecodeFixed64(bkey.data() + bkey.size() - 8);
        if (anum > bnum)
        {
            r = -1;
        }
        else if (anum < bnum)
        {
            r = +1;
        }
    }
    return r;
}

void InternalKeyComparator::FindShortestSeparator(std::string *start, const Slice &limit) const
{
    // Attempt to shorten the user portion of the key
    Slice user_start = ExtractUserKey(*start);
    Slice user_limit = ExtractUserKey(limit);
    std::string tmp(user_start.data(), user_start.size());
    user_comparator_->FindShortestSeparator(&tmp, user_limit);
    if (tmp.size() < user_start.size() && user_comparator_->Compare(user_start, tmp) < 0)
    {
        // User key has become shorter physically, but larger logically.
        // Tack on the earliest possible number to the shortened user key.
        PutFixed64(&tmp, PackSequenceAndType(kMaxSequenceNumber, kValueTypeForSeek));
        assert(this->Compare(*start, tmp) < 0);
        assert(this->Compare(tmp, limit) < 0);
        start->swap(tmp);
    }
}
std::string ParsedInternalKey::DebugString() const
{
    std::ostringstream ss;
    // ss << '\'' << EscapeString(user_key.ToString()) << "' @ " << sequence << " : "
    //    << static_cast<int>(type);
    return ss.str();
}
} // namespace minidb